using System;
using NUnit.Framework;
using Pine.Core;
using Pine.Compiler.Utils;

namespace UnitTests
{
	[TestFixture]
	public class TestExpressions
	{
		private static void AssertSingleResult(ValueList rl, Value value, string sizeMessage, string resultErrorMessage) {
			Assert.AreEqual(1, rl.Size, sizeMessage);
			Assert.AreEqual(value, rl.GetArrayElement(0), resultErrorMessage);
		}
		
		[Test]
		public void TestInteger() {
			ValueList rl = new ValueList();
			
			Compiler.ExecuteString("test-integer", "main", @"\main() return 1;", rl, null);
			AssertSingleResult(rl, new Number(1), "Expected single result", "Incorrect result");
		}
		
		[Test]
		public void TestDouble() {
			ValueList rl = new ValueList();
			
			Compiler.ExecuteString("test-double", "main", @"\main() return 1.5;", rl, null);
			
			AssertSingleResult(rl, new Number(1.5), "Expected single result", "Incorrect result");
		}
		
		[Test]
		public void TestHexadecimal() {
			ValueList rl = new ValueList();
			
			Compiler.ExecuteString("test-hex", "main", @"\main() return 0x10;", rl, null);
			
			AssertSingleResult(rl, new Number(16), "Expected single result", "Incorrect result");
		}
		
		[Test]
		public void TestOctal() {
			//Check for octal numbers
			ValueList rl = new ValueList();
			Compiler.ExecuteString("test-octal", "main", @"\main() return 0o10;", rl, null);
			AssertSingleResult(rl, new Number(8), "Expected single result", "Incorrect result");
			
			//Check incorrect(aka legacy) octal numbers
			rl.Clear();
			Compiler.ExecuteString("test-octal-legacy", "main", @"\main() return 010;", rl, null);
			AssertSingleResult(rl, new Number(10), "Expected single result", "Incorrect result 010 is decimal, not octal, in PineDL");
		}
		
		[Test]
		public void TestString() {
			ValueList rl = new ValueList();
			Compiler.ExecuteString("test-string", "main", "function main() return \"Hello, World!\";", rl, null);
			AssertSingleResult(rl, new StringValue("Hello, World!"), "Expected single result", "Incorrect result for string constant");
			
			rl.Clear();
			Compiler.ExecuteString("test-string-simple-escape", "main", "function main() return \"Escape \\\\\";", rl, null);
			AssertSingleResult(rl, new StringValue("Escape \\"), "Expected single result", @"Incorrect result with \\ escape sequences");
			
			rl.Clear();
			Compiler.ExecuteString("test-string-line-escape", "main", "function main() return \"Escape \\n\\N\";", rl, null);
			AssertSingleResult(rl, new StringValue("Escape \n\n"), "Expected single result", @"Incorrect result with \n escape sequences");
			
			rl.Clear();
			Compiler.ExecuteString("test-string-quote-escape", "main", "function main() return \"Escape \\\"\";", rl, null);
			AssertSingleResult(rl, new StringValue("Escape \""), "Expected single result", "Incorrect result with \\\" escape sequences");
		}
		
		[Test]
		public void TestSum() {
			ValueList rl = new ValueList();
			Compiler.ExecuteString("test-sum-number-number", "main", "function main() return 1 + 2;", rl, null);
			AssertSingleResult(rl, new Number(3), "Expected single result", "Incorrect result for number sum");
			
			rl.Clear();
			Compiler.ExecuteString("test-sum-string-number", "main", "function main() return \"foo\" + 1;", rl, null);
			AssertSingleResult(rl, new StringValue("foo1"), "Expected single result", "Incorrect result for string + number sum");
			
			rl.Clear();
			Compiler.ExecuteString("test-sum-number-string", "main", "function main() return 1 + \"foo\";", rl, null);
			AssertSingleResult(rl, new StringValue("1foo"), "Expected single result", "Incorrect result for number + string sum");
			
			rl.Clear();
			Compiler.ExecuteString("test-sum-string-string", "main", "function main() return \"foo\" + \"bar\";", rl, null);
			AssertSingleResult(rl, new StringValue("foobar"), "Expected single result", "Incorrect result for string + string sum");
		}
	}
}

